#include <gpiod.h>  // 包含libgpiod库的头文件
#include <stdio.h>  // 包含标准输入输出库
#include <unistd.h> // 包含UNIX标准库，用于usleep函数
#include <sys/types.h>
#include <stdbool.h>
#include "record.h"
#include "control.h"

#include "config.h"
#include "token.h"
#include "http.h"


#define GPIO_LINE 9 // 定义GPIO线的编号，这里是PF9
#define VOLUME_UP_LINE 8 // 音量加按键连接到GPIOF线8
#define VOLUME_DOWN_LINE 7 // 音量减按键连接到GPIOF线7

char* app_id = "f221d824-876c-42bc-b6c5-4f1581ea0f96";

// 正在录音
void recording(snd_pcm_t *capture, char *buffer, FILE *pcm_file, snd_pcm_uframes_t period);

// 音量设置相关变量
long volume = 0; // 初始音量
long volume_step = 10; // 每次调整的音量步长

//读取音频文件
//file: 音频文件路径
//size: 音频文件大小
//return: 音频文件内容, NULL 表示失败
char* load_audio_file(const char* file, size_t* size);

//发送请求消息
//token: 获取的access token
//audio: 音频文件内容
//size: 音频文件大小
//return: 响应消息正文, NULL 表示失败
char* send_request(char* token, char* audio, size_t size);

//处理服务器返回的响应消息
char* process_response(char* response, size_t size);

//创建会话
char* create_conversation(char* authtoken);

//调用对话API
char* chat(char* authtoken, char* conv_id, char* query);

int main(void)
{
    // 按键引脚相关变量
    struct gpiod_chip *chip; // 定义指向GPIO芯片的指针
    struct gpiod_line *line; // 定义指向GPIO线的指针
    struct gpiod_line *volume_up;
    struct gpiod_line *volume_down;
    int value, last_value;   // 定义当前值和上一次的值，用于检测状态变化
    int value_up, last_value_up;
    int value_down, last_value_down;

    // 录音相关变量
    snd_pcm_uframes_t period = 999; // 周期大小
    snd_pcm_t *capture = NULL; // 声音采集设备句柄
    char *buffer = NULL; // 存放音频数据的缓冲区
    FILE *pcm_file = NULL; // 录音文件

    // 回答内容
    char *result = NULL;

    // 打开GPIO芯片
    chip = gpiod_chip_open_by_label("GPIOF");
    if (!chip)
    {
        perror("打开GPIO芯片失败");
        return 1;
    }

    // 获取GPIO线
    line = gpiod_chip_get_line(chip, GPIO_LINE);
    if (!line)
    {
        perror("获取GPIO线失败");
        gpiod_chip_close(chip);
        return 1;
    }

    volume_up = gpiod_chip_get_line(chip, VOLUME_UP_LINE);
    if (!volume_up)
    {
        perror("获取GPIO线失败");
        gpiod_chip_close(chip);
        return 1;
    }

    volume_down = gpiod_chip_get_line(chip, VOLUME_DOWN_LINE);
    if (!volume_down)
    {
        perror("获取GPIO线失败");
        gpiod_chip_close(chip);
        return 1;
    }

    // 将GPIO线设置为输入模式
    if (gpiod_line_request_input(line, "key1"))
    {
        perror("请求将GPIO线设置为输入模式失败");
        gpiod_chip_close(chip);
        return 1;
    }

    if (gpiod_line_request_input(volume_up, "key3"))
    {
        perror("请求将GPIO线设置为输入模式失败");
        gpiod_chip_close(chip);
        return 1;
    }

    if (gpiod_line_request_input(volume_down, "key2"))
    {
        perror("请求将GPIO线设置为输入模式失败");
        gpiod_chip_close(chip);
        return 1;
    }

    // 获取初始的GPIO线值
    last_value = gpiod_line_get_value(line);
    last_value_up = gpiod_line_get_value(volume_up);
    last_value_down = gpiod_line_get_value(volume_down);

    // 无限循环检测GPIO线值的变化
    while (1)
    {
        // 获取当前的GPIO线值
        value = gpiod_line_get_value(line);
        value_up = gpiod_line_get_value(volume_up);
        value_down = gpiod_line_get_value(volume_down);

        // 如果当前值与上一次的值不同，说明按键状态发生了变化
        if (value != last_value)
        {
            // 如果当前值为0，表示按键被按下
            if (value == 0)
            {
                printf("key1 pressed\n");
                capture = record_start("hw:0,1", SND_PCM_FORMAT_S16_LE, 1, 16000, &period);
                if (!capture)
                {
                    continue; // 下一次循环重试
                }

                buffer = malloc(snd_pcm_frames_to_bytes(capture, period)); // 分配缓冲区
                if (!buffer)
                {
                    perror("malloc");
                    record_stop(capture);
                    continue;
                }

                pcm_file = fopen("stt.pcm", "wb");
                if (!pcm_file)
                {
                    perror("Error opening output file");
                    free(buffer);         // 释放缓冲区
                    record_stop(capture); // 关闭PCM设备
                    continue;
                }
            }
            // 如果当前值为1，表示按键被释放
            else
            {
                printf("key1 released\n");
                record_stop(capture);
                capture = NULL;

                // 将语音转换成文本
                //读取配置信息，API KEY 和 SECRET KEY
                cJSON *config = read_config("config.json");
                if (!config) {
                    printf("config: %s\n", cJSON_Print(config));
                    cJSON_Delete(config);
                }
                cJSON* api_key = cJSON_GetObjectItem(config, "api_key");
                cJSON* secret_key = cJSON_GetObjectItem(config, "secret_key");
                cJSON* authtoken = cJSON_GetObjectItem(config, "authtoken");
                if (!api_key ||!secret_key ||!authtoken) {
                    fprintf(stderr, "配置文件错误: 找不到 'api_key' 或'secret_key' 或'authtoken' 字段\n");
                    cJSON_Delete(config);
                }
                printf("%s\n", authtoken->valuestring);

                //获取token
                char* token = get_access_token(api_key->valuestring, secret_key->valuestring);
                if (!token) {
                    fprintf(stderr, "获取 token 失败\n");
                    cJSON_Delete(config);
                }

                //读取音频文件
                size_t size;
                char* buffer = load_audio_file("stt.pcm", &size);
                if (!buffer) {
                    cJSON_Delete(config);
                }

                //调用百度语音识别 API
                char* response = send_request(token, buffer, size);
                if (!response) {
                    fprintf(stderr, "调用百度语音识别 API 失败\n");
                    free(buffer);
                    cJSON_Delete(config);
                }

                //处理服务器返回的响应消息
                result = process_response(response, size);

                printf("result: %s\n", result);

                //创建会话
                char* conv_id = create_conversation(authtoken->valuestring);

                //printf("conv_id: %s\n", conv_id);

                //调用百度云千帆AppBuilder API进行对话
                char* answer = chat(authtoken->valuestring, conv_id, result);
                if (!answer)
                {
                    continue;
                }
                printf("< %s\n", answer);

                //释放配置信息占用的内存
                cJSON_Delete(config);

            }

            // 更新上一次的值为当前值
            last_value = value;
        }

        if (value_up != last_value_up)
        {
            if (value_up == 0)
            {
                printf("key3 pressed\n");
                volume = get_playback_volume("hw:0", "Analog");
                set_playback_volume("hw:0", "Analog", volume + volume_step);
                printf("当前音量：%ld\n", volume + volume_step);
            }
            else
            {
                printf("key3 released\n");
                
            }

            last_value_up = value_up;
        }

        if (value_down != last_value_down)
        {
            if (value_down == 0)
            {
                printf("key2 pressed\n");
                volume = get_playback_volume("hw:0", "Analog");
                set_playback_volume("hw:0", "Analog", volume - volume_step);
                printf("当前音量：%ld\n", volume - volume_step);
            }
            else
            {
                printf("key2 released\n");
                
            }

            last_value_down = value_down;
        }

        if (value == 0 && capture)
        {
            // 按键按下且音频设备打开成功，进行录音
            recording(capture, buffer, pcm_file, period);
        }
        // 延时100毫秒，防止检测过于频繁
        //usleep(100000);
    }

    // 关闭GPIO芯片
    gpiod_chip_close(chip);
    return 0;
}

// 正在录音
void recording(snd_pcm_t *capture, char *buffer, FILE *pcm_file, snd_pcm_uframes_t period)
{
    snd_pcm_sframes_t frames = snd_pcm_readi(capture, buffer, period); // 从PCM设备读取数据
    if (frames < 0)
    {
        fprintf(stderr, "Error from read: %s\n", snd_strerror(frames));
        snd_pcm_recover(capture, frames, 0); // 处理欠载和过载问题
    }

    fwrite(buffer, snd_pcm_frames_to_bytes(capture, frames), 1, pcm_file); // 将读取的数据写入文件
}

//读取音频文件
//file: 音频文件路径
//size: 音频文件大小
//return: 音频文件内容, NULL 表示失败
char* load_audio_file(const char* file, size_t* size)
{
    //打开音频文件
    FILE* fp = fopen(file, "rb");
    if (!fp) {
        perror(file);
        return NULL;
    }
    //获取文件大小
    fseek(fp, 0, SEEK_END);
    *size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    //读取文件内容
    char* buffer = (char*)malloc(*size);
    if (!buffer) {
        perror("malloc");
        fclose(fp);
        return NULL;
    }
    fread(buffer, 1, *size, fp);
    fclose(fp);
    return buffer;
}

//发送请求消息
//token: 获取的access token
//audio: 音频文件内容
//size: 音频文件大小
//return: 响应消息正文, NULL 表示失败
char* send_request(char* token, char* audio, size_t size)
{
    char* url = NULL;
    asprintf(&url, "http://vop.baidu.com/server_api?cuid=hqyj&token=%s&dev_pid=1537", token);

    struct curl_slist* headers = NULL;
    headers = curl_slist_append(headers, "Content-Type: audio/pcm; rate=16000");

    char* response = post(url, headers, audio, &size);

    free(url);
    curl_slist_free_all(headers);

    return response;
}

//处理服务器返回的响应消息
char* process_response(char* response, size_t size)
{
    //解析 JSON 响应
    cJSON *json = cJSON_ParseWithLength(response, size);
    if (!json) {
        fprintf(stderr, "解析 JSON 失败: [%s]\n", cJSON_GetErrorPtr());
        return NULL;
    }

    //判断err_no字段
    cJSON* err_no = cJSON_GetObjectItem(json, "err_no");
    if (!err_no) {
        fprintf(stderr, "err_no 字段不存在\n");
        cJSON_Delete(json);
        return NULL;
    }
    //判断err_no的值
    if (err_no->valueint != 0) {
        //打印错误信息
        cJSON* err_msg = cJSON_GetObjectItem(json, "err_msg");
        if (err_msg)
        {
            fprintf(stderr, "err_msg: %s\n", err_msg->valuestring);
        }
        cJSON_Delete(json);
        return NULL;
    }

    // 获取 "result" 字段中的第一个元素
    cJSON *result = cJSON_GetObjectItem(json, "result");
    if (!result) {
        fprintf(stderr, "JSON 格式错误: 找不到'result' 字段\n");
        cJSON_Delete(json);
        return NULL;
    }

    cJSON *content = cJSON_GetArrayItem(result, 0);
    if (!content || !cJSON_IsString(content)) {
        fprintf(stderr, "result 字段格式错误: 第一个元素不是字符串\n");
        cJSON_Delete(json);
        return NULL;
    }

    // if (cJSON_GetArraySize(result) > 0) {
    //     // 获取第一个元素的 "content" 字段
    //     cJSON *content = cJSON_GetArrayItem(result, 0);
    //     //打印结果
    //     printf("result: %s\n", content->valuestring);
    // }

    // 为返回值分配内存
    char *result_str = (char *)malloc(content->valuestring ? strlen(content->valuestring) + 1 : 1);
    if (!result_str) {
        fprintf(stderr, "内存分配失败\n");
        cJSON_Delete(json);
        return NULL;
    }

    // 复制字符串
    strcpy(result_str, content->valuestring);

    // 清理 cJSON 对象
    cJSON_Delete(json);

    // 返回 result 字段中的第一个元素的内容
    return result_str;
}

//创建会话
char* create_conversation(char* authtoken)
{
    char* url = "https://qianfan.baidubce.com/v2/app/conversation";

    //拼接Authorization字段
    char* auth;
    asprintf(&auth, "Authorization: Bearer %s", authtoken);

    //添加请求头部字段
    struct curl_slist* headers = NULL;
    headers = curl_slist_append(headers, "Content-Type: application/json;charset=utf-8");
    headers = curl_slist_append(headers, auth);

    //准备请求正文
    cJSON* obj = cJSON_CreateObject();
    cJSON_AddStringToObject(obj, "app_id", app_id);
    //将JSON对象转换为JSON字符串
    char* json = cJSON_Print(obj);

    //发送请求
    size_t size = strlen(json);
    char* response = post(url, headers, json, &size);
    cJSON_Delete(obj);
    free(json);
    free(auth);
    curl_slist_free_all(headers);

    if (!response)
    {
        return NULL;
    }

    obj = cJSON_ParseWithLength(response, size);
    free(response);

    if (!obj)
    {
        fprintf(stderr, "解析 JSON 失败: [%s]\n", cJSON_GetErrorPtr());
        return NULL;
    }

    cJSON* conversation_id = cJSON_GetObjectItem(obj, "conversation_id");
    if (!conversation_id)
    {
        fprintf(stderr, "conversation_id 字段不存在\n");
        cJSON_Delete(obj);
        return NULL;
    }

    char* retval = strdup(conversation_id->valuestring);

    cJSON_Delete(obj);

    return retval;
}

//调用对话API
//authtoken: 平台密钥
//conv_id: 会话ID
//query: 用户输入的文本
//返回值: 对话结果
char* chat(char* authtoken, char* conv_id, char* query)
{
    char* url = "https://qianfan.baidubce.com/v2/app/conversation/runs";

    //拼接Authorization字段
    char* auth;
    asprintf(&auth, "Authorization: Bearer %s", authtoken);

    //设置请求头部字段
    struct curl_slist* headers = NULL;
    headers = curl_slist_append(headers, "Content-Type: application/json;charset=utf-8");
    headers = curl_slist_append(headers, auth);

    //准备请求正文
    cJSON* obj = cJSON_CreateObject();
    cJSON_AddStringToObject(obj, "app_id", app_id);
    cJSON_AddStringToObject(obj, "conversation_id", conv_id);
    cJSON_AddStringToObject(obj, "query", query);
    cJSON_AddBoolToObject(obj, "stream", false);
    //将JSON对象转换为JSON字符串
    char* json = cJSON_Print(obj);

    //发送请求
    size_t size = strlen(json);
    char* response = post(url, headers, json, &size);
    cJSON_Delete(obj);
    free(json);
    curl_slist_free_all(headers);
    free(auth);

    if (!response)
    {
        return NULL;
    }

    obj = cJSON_ParseWithLength(response, size);
    free(response);

    if (!obj)
    {
        fprintf(stderr, "解析 JSON 失败: [%s]\n", cJSON_GetErrorPtr());
        return NULL;
    }

    cJSON* answer = cJSON_GetObjectItem(obj, "answer");
    if (!answer)
    {
        fprintf(stderr, "answer 字段不存在\n");
        puts(cJSON_Print(obj));
        cJSON_Delete(obj);
        return NULL;
    }

    char* retval = strdup(answer->valuestring);

    cJSON_Delete(obj);

    return retval;
}